/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { TypeNode } from 'ts-morph';
import { PropertyAnalysis, TypeStructure, PropertyKind, TypeDependency } from '..';
import { TypeHandlerRegistry } from '../handlers';
import { DeepCopyUtil } from './DeepCopyUtil';
import { Logger } from '../logger/Logger';

export class GenericTypeSubstitutionUtil {
  /**
   * 构建泛型参数映射表
   * @param parentGenericParams 父类泛型参数定义 ["T", "U"]
   * @param childTypeArguments 子类传入的具体类型 ["string", "number"]
   * @returns 映射表 Map { "T" => "string", "U" => "number" }
   */
  static buildGenericMapping(parentGenericParams: string[], childTypeArguments: TypeNode[]): Map<string, TypeNode> {
    const mapping = new Map<string, TypeNode>();

    const length = Math.min(parentGenericParams.length, childTypeArguments.length);

    Logger.debug(`[GenericMapping] Building mapping with ${length} parameters`);
    for (let i = 0; i < length; i++) {
      Logger.debug(`[GenericMapping] ${parentGenericParams[i]} -> ${childTypeArguments[i].getText()}`);
      mapping.set(parentGenericParams[i], childTypeArguments[i]);
    }

    return mapping;
  }

  /**
   * 对属性类型进行泛型替换
   * @param property 原始属性分析
   * @param genericMapping 泛型参数映射 { "T": "string", "U": "number" }
   * @param currentClassGenericParams 当前类的泛型参数列表
   * @returns 替换后的属性分析
   */
  static substitutePropertyType(
    property: PropertyAnalysis,
    genericMapping: Map<string, TypeNode>,
    currentClassGenericParams: string[] = []
  ): PropertyAnalysis {
    if (genericMapping.size === 0) {
      return property; // 没有泛型替换，直接返回
    }

    // 使用深拷贝避免引用问题
    const newProperty: PropertyAnalysis = DeepCopyUtil.copyPropertyAnalysis(property);

    // 递归替换类型结构中的泛型参数
    newProperty.type = this.substituteTypeStructure(newProperty.type, genericMapping, currentClassGenericParams);

    return newProperty;
  }

  private static substituteTypeStructure(
    typeStructure: TypeStructure,
    mapping: Map<string, TypeNode>,
    currentClassGenericParams: string[] = []
  ): TypeStructure {
    // 1. 处理泛型类型替换（核心逻辑）
    if (typeStructure.kind === PropertyKind.GENERIC) {
      // 对于泛型类型，sourceText 就是泛型参数名（如 "T", "U", "TData"）
      const genericTypeName = typeStructure.sourceText;
      Logger.debug(`[GenericSubstitution] Processing generic type: ${genericTypeName}`);
      Logger.debug(`[GenericSubstitution] Available mappings: ${Array.from(mapping.keys()).join(', ')}`);
      Logger.debug(`[GenericSubstitution] Current class generic params: ${currentClassGenericParams.join(', ')}`);

      if (mapping.has(genericTypeName)) {
        const substitutedTypeNode = mapping.get(genericTypeName)!;
        Logger.debug(`[GenericSubstitution] Found mapping for ${genericTypeName} -> ${substitutedTypeNode.getText()}`);

        const result = this.constructTypeStructureFromTypeName(substitutedTypeNode, currentClassGenericParams);
        Logger.debug(`[GenericSubstitution] Result kind: ${result.kind}, sourceText: ${result.sourceText}`);
        return result;
      }
      // 如果没有找到对应的映射，保持原样
      Logger.warn(`[GenericSubstitution] No mapping found for generic type: ${genericTypeName}, keeping as-is`);
      return typeStructure;
    }

    // 2. 递归处理非泛型类型的子结构
    // 使用深拷贝避免修改原始对象
    const newStructure: TypeStructure = DeepCopyUtil.copyTypeStructure(typeStructure);

    // 递归替换所有子结构中的泛型类型
    if (newStructure.unionDetails) {
      newStructure.unionDetails = newStructure.unionDetails.map(
        member => this.substituteTypeStructure(member, mapping, currentClassGenericParams)
      );
    }

    if (newStructure.args) {
      newStructure.args = newStructure.args.map(
        arg => this.substituteTypeStructure(arg, mapping, currentClassGenericParams)
      );
      // 重新生成 sourceText 以反映泛型参数替换
      newStructure.sourceText = this.regenerateSourceText(newStructure);
    }









    // 重新计算依赖信息
    newStructure.dependencies = this.collectDependenciesFromChildren(newStructure);

    return newStructure;
  }

  private static constructTypeStructureFromTypeName(
    typeNode: TypeNode,
    currentClassGenericParams: string[] = []
  ): TypeStructure {
    return TypeHandlerRegistry.getInstance().parseType(typeNode, {
      depth: 0,
      genericParams: currentClassGenericParams // ✅ 传递当前类的泛型参数上下文
    })
  }

  /**
   * 根据替换后的 args 重新生成 sourceText
   * 保持原始格式（数组字面量 T[] 或泛型形式 Container<T>）
   * @param structure 类型结构
   * @returns 重新生成的 sourceText
   */
  private static regenerateSourceText(structure: TypeStructure): string {
    if (!structure.args || structure.args.length === 0) {
      return structure.sourceText;
    }

    // 处理数组字面量形式: T[] -> NewT[]
    if (structure.sourceText.endsWith('[]')) {
      return `${structure.args[0].sourceText}[]`;
    }

    // 处理泛型形式: Container<T> 或 Container<K, V>
    // 提取容器名称（在 < 之前的部分）
    const genericStart = structure.sourceText.indexOf('<');
    if (genericStart > 0) {
      const containerName = structure.sourceText.substring(0, genericStart);
      const argsText = structure.args.map(arg => arg.sourceText).join(', ');
      return `${containerName}<${argsText}>`;
    }

    // 其他情况保持原样
    return structure.sourceText;
  }

  private static collectDependenciesFromChildren(children: TypeStructure): TypeDependency[] {
    const allDependencies: TypeDependency[] = [];

    if (children.unionDetails) {
      for (const member of children.unionDetails) {
        if (member.dependencies) {
          allDependencies.push(...member.dependencies);
        }
      }
    }
    if (children.args) {
      for (const arg of children.args) {
        if (arg.dependencies) {
          allDependencies.push(...arg.dependencies);
        }
      }
    }

    return allDependencies;
  }
}